#include "drawwave.h"
#include "ui_drawwave.h"

#define     ON_WAVE_DRAWING     0
#define     ON_WAVE_GENERATE    1
#define     ON_WAVE_SAVED       2


drawWave::drawWave(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::drawWave)
{
    ui->setupUi(this);


    mouseLoc.reserve(DRAWAREA_LEN+1);
    wavePointsLoc.reserve(DRAWAREA_LEN+1);
    datatoWrite.reserve(DRAWAREA_LEN);
    datatoGenerate.reserve(DRAWAREA_LEN);
    waveDisplayLoc.reserve(DRAWAREA_LEN+1);
    axisLabelLocX.reserve(9);
    axisLabelLocY.reserve(9);
    drawingFlag = ON_WAVE_DRAWING;
    mouseX_past = DRAWAREA_OFFSET_X;
    for(int i = 0;i < DRAWAREA_LEN ; i++)
        mouseLoc[i] = DRAWAREA_OFFSET_Y+DRAWAREA_WID;
        //mouseLoc[i] = DRAWAREA_WID+DRAWAREA_OFFSET_Y;
    axisLabelLocX[0] = ui->label_axisX1;
    axisLabelLocX[1] = ui->label_axisX2;
    axisLabelLocX[2] = ui->label_axisX3;
    axisLabelLocX[3] = ui->label_axisX4;
    axisLabelLocX[4] = ui->label_axisX5;
    axisLabelLocX[5] = ui->label_axisX6;
    axisLabelLocX[6] = ui->label_axisX7;
    axisLabelLocX[7] = ui->label_axisX8;
    axisLabelLocX[8] = ui->label_axisX9;
    axisLabelLocY[0] = ui->label_axisY1;
    axisLabelLocY[1] = ui->label_axisY2;
    axisLabelLocY[2] = ui->label_axisY3;
    axisLabelLocY[3] = ui->label_axisY4;
    axisLabelLocY[4] = ui->label_axisY5;
    axisLabelLocY[5] = ui->label_axisY6;
    axisLabelLocY[6] = ui->label_axisY7;
    axisLabelLocY[7] = ui->label_axisY8;
    axisLabelLocY[8] = ui->label_axisY9;
    drawWave::update();


    waveResolution = 8;
    waveSamplingPoints = DRAWAREA_LEN;

    ui->lineEdit_filePath->setText(filePath + ":/_wave/unnamed.wda");

    ui->label_X->hide();
    ui->label_Y->hide();
    ui->textBrowser_infoOut->hide();

    //waveSamplingPoints = ui->spinBox_samplingPoints->value();
}

drawWave::~drawWave()
{   
    delete ui;
}

void drawWave::on_pushButton_clicked()
{
    this->close();
}

void drawWave::paintEvent(QPaintEvent *event)
{
    QPainter painter;

    //painter.begin(this);
    painter.begin(this);
    //painter = this;
    painter.setPen(QPen(Qt::lightGray,3,Qt::SolidLine,Qt::SquareCap));
    painter.setBrush(QBrush(Qt::black,Qt::SolidPattern));
    //painter.setBrush(QBrush(Qt::black,Qt::Dense1Pattern));
    //20 35
    painter.drawRect(DRAWAREA_OFFSET_X-4,DRAWAREA_OFFSET_Y,
                     DRAWAREA_LEN+8,DRAWAREA_WID+4);
    //painter.drawLine(mouseX_Past,mouseY_Past,mouseX_Now,mouseY_Now);

    /**********drawing reference line**********/
    painter.setPen(QPen(QColor(0,0,255,120),2,Qt::DotLine,Qt::RoundCap));
    int lineStepX = DRAWAREA_LEN / 8;
    int lineStepY = DRAWAREA_WID / 8;
    int axisStepX = waveSamplingPoints / 8;
    int axisStepY = (2 << (waveResolution-1)) / 8;
    axisLabelLocY[0]->setGeometry(DRAWAREA_OFFSET_X + DRAWAREA_LEN+7,DRAWAREA_OFFSET_Y-5,24,12);
    axisLabelLocY[0]->setNum((2 << (waveResolution-1)) - 1);
    for(int i = 1 ; i < 8 ; i++)
    {
        painter.drawLine(DRAWAREA_OFFSET_X,DRAWAREA_OFFSET_Y + i*lineStepY,
                         DRAWAREA_OFFSET_X + DRAWAREA_LEN,DRAWAREA_OFFSET_Y + i*lineStepY);
        axisLabelLocY[i]->setGeometry(DRAWAREA_OFFSET_X + DRAWAREA_LEN+7,DRAWAREA_OFFSET_Y + i*lineStepY-5,24,12);
        axisLabelLocY[i]->setNum( (2 << (waveResolution-1)) - i * axisStepY);
    }
    axisLabelLocY[8]->setGeometry(DRAWAREA_OFFSET_X + DRAWAREA_LEN+7,DRAWAREA_OFFSET_Y + DRAWAREA_WID-8,24,12);
    axisLabelLocY[8]->setNum(0);

    axisLabelLocX[0]->setGeometry(DRAWAREA_OFFSET_X -5,DRAWAREA_OFFSET_Y + DRAWAREA_WID+5,24,12);
    axisLabelLocX[0]->setNum(0);
    for(int i = 1 ; i < 8 ; i++)
    {
        painter.drawLine(DRAWAREA_OFFSET_X + i*lineStepX,DRAWAREA_OFFSET_Y,
                         DRAWAREA_OFFSET_X + i*lineStepX,DRAWAREA_OFFSET_Y + DRAWAREA_WID);
        axisLabelLocX[i]->setGeometry(DRAWAREA_OFFSET_X + i * lineStepX-8,DRAWAREA_OFFSET_Y + DRAWAREA_WID+5,24,12);
        axisLabelLocX[i]->setNum(i*axisStepX);
    }
    axisLabelLocX[8]->setGeometry(DRAWAREA_OFFSET_X + DRAWAREA_LEN-15,DRAWAREA_OFFSET_Y + DRAWAREA_WID+5,24,12);
    axisLabelLocX[8]->setNum(waveSamplingPoints - 1);


    /*************draw painting line*************/
    //painter.setPen(QPen(QColor(0,255,255,255),5,Qt::SolidLine,Qt::RoundCap));
    painter.setPen(QPen(QColor(255,255,0,255),3,Qt::SolidLine,Qt::RoundCap));
    for(int i = 0 ; i < (DRAWAREA_LEN-2) ; i++)
    {
        painter.drawLine(i+DRAWAREA_OFFSET_X,mouseLoc[i],i+DRAWAREA_OFFSET_X+1,mouseLoc[i+1]);
    }
//    painter.setPen(QPen(QColor(0,255,255,255),5,Qt::SolidLine,Qt::RoundCap));
//    for(int i = 0 ; i < (samplingPoints-2) ; i++)
//    {
//        painter.drawLine(i+DRAWAREA_OFFSET_X,datatoWrite[i],i+DRAWAREA_OFFSET_X+1,datatoWrite[i+1]);
//    }


    /*************draw generation line*************/
    if((drawingFlag == ON_WAVE_GENERATE)||(drawingFlag == ON_WAVE_SAVED))
    {
        painter.setPen(QPen(QColor(0,255,255,255),3,Qt::SolidLine,Qt::RoundCap));
        if(samplingPoints < DRAWAREA_LEN)
        {
            double XStep = (double)DRAWAREA_LEN / (double)samplingPoints;
            for(int i = 0; i < (samplingPoints-1) ; i++)
            {
                painter.drawLine(DRAWAREA_OFFSET_X + (int)(i * XStep),waveDisplayLoc[i]
                                 ,DRAWAREA_OFFSET_X + (int)((i + 1) * XStep),waveDisplayLoc[i+1]);
            }
        }
        else
        {
            for(int i = 0; i < (DRAWAREA_LEN-1) ; i++)
            {
                painter.drawLine(DRAWAREA_OFFSET_X + i,waveDisplayLoc[i]
                                 ,DRAWAREA_OFFSET_X + (i+1),waveDisplayLoc[i+1]);
            }
        }
    }
}

void drawWave::mousePressEvent(QMouseEvent *event)
{
    ui->label_X->setNum(event->x());
    ui->label_Y->setNum(event->y());
//    mouseX_Now = event->x();
//    mouseY_Now = event->y();
    if((drawingFlag == ON_WAVE_GENERATE)||(drawingFlag == ON_WAVE_SAVED))
    {
        drawingFlag = ON_WAVE_DRAWING;
        ui->pushButton_drawWave->setText("Generate");
    }
    if((drawingFlag == ON_WAVE_DRAWING)
            &&(event->x()>=DRAWAREA_OFFSET_X)&&(event->x()<=DRAWAREA_LEN+DRAWAREA_OFFSET_X)
            &&(event->y()>=DRAWAREA_OFFSET_Y)&&(event->y()<=DRAWAREA_WID+DRAWAREA_OFFSET_Y))
    {
        mouseX_past = event->x();
        mouseLoc[event->x()-DRAWAREA_OFFSET_X] = event->y();
    }
    mouseClickX = event->x();
    mouseClickY = event->y();
    drawWave::update();
}

void drawWave::mouseMoveEvent(QMouseEvent *event)
{
    ui->label_X->setNum(event->x());
    ui->label_Y->setNum(event->y());
//    mouseX_Past = mouseX_Now;
//    mouseY_Past = mouseY_Now;
//    mouseX_Now = event->x();
//    mouseY_Now = event->y();
    if((drawingFlag == ON_WAVE_DRAWING)
            &&(mouseClickX>=DRAWAREA_OFFSET_X)&&(mouseClickX<=DRAWAREA_LEN+DRAWAREA_OFFSET_X)
            &&(mouseClickY>=DRAWAREA_OFFSET_Y)&&(mouseClickY<=DRAWAREA_WID+DRAWAREA_OFFSET_Y))
    {
        int mouseX = event->x();
        int mouseY = event->y();
        if(event->x() < DRAWAREA_OFFSET_X)
            mouseX = DRAWAREA_OFFSET_X;
        else if(event->x() > (DRAWAREA_LEN + DRAWAREA_OFFSET_X))
            mouseX = DRAWAREA_LEN + DRAWAREA_OFFSET_X;
        if(event->y() < DRAWAREA_OFFSET_Y)
            mouseY = DRAWAREA_OFFSET_Y;
        else if(event->y() > (DRAWAREA_WID + DRAWAREA_OFFSET_Y))
            mouseY = DRAWAREA_WID + DRAWAREA_OFFSET_Y;

        if((drawingFlag == ON_WAVE_GENERATE)||(drawingFlag == ON_WAVE_SAVED))
        {
            drawingFlag = ON_WAVE_DRAWING;
            ui->pushButton_drawWave->setText("Generate");
        }
    //    if((drawingFlag == ON_WAVE_DRAWING)
    //            &&(event->x()>=DRAWAREA_OFFSET_X)&&(event->x()<=DRAWAREA_LEN+DRAWAREA_OFFSET_X)
    //            &&(event->y()>=DRAWAREA_OFFSET_Y)&&(event->y()<=DRAWAREA_WID+DRAWAREA_OFFSET_Y))
    //    {
            //linear interpolation
            mouseLoc[mouseX-DRAWAREA_OFFSET_X] = mouseY;
            if((mouseX > mouseX_past)&&(mouseX != (mouseX_past + 1)))
            {
                double step = (double)(mouseY - mouseLoc[mouseX_past-DRAWAREA_OFFSET_X])/(mouseX - mouseX_past);
                for(int i = mouseX_past ; i < mouseX ; i++)
                {
                    mouseLoc[i-DRAWAREA_OFFSET_X] = (int)((double)mouseLoc[mouseX_past-DRAWAREA_OFFSET_X]
                                                             + (i-mouseX_past)*step);
                }
            }
            else if((mouseX < mouseX_past)&&(mouseX != (mouseX_past - 1)))
            {
                double step = (double)(mouseLoc[mouseX_past-DRAWAREA_OFFSET_X] - mouseY)/( mouseX_past - mouseX);
                for(int i = mouseX_past ; i > mouseX ; i--)
                {
                    mouseLoc[i-DRAWAREA_OFFSET_X] = (int)((double)mouseLoc[mouseX_past-DRAWAREA_OFFSET_X]
                                                             + (i-mouseX_past)*step);
                }
            }
            mouseX_past = mouseX;
            drawWave::update();
    //    }
    }
}

void drawWave::changeFilePath(QString &path)
{
    filePath = path;
    ui->lineEdit_filePath->setText(filePath + "_wave/unnamed.wda");
}

void drawWave::waveGenerate()
{
//    QString writePath = ui->lineEdit_filePath->text();
//    QFile waveFile(writePath);
    //QFile waveFile("C:\\001.wda");
    //int writeData[DRAWAREA_LEN];
    samplingPoints = ui->spinBox_samplingPoints->value();
    datatoWrite.reserve(samplingPoints);
    datatoGenerate.reserve(samplingPoints);
    //ui->spinBox_samplingPoints->setValue(samplingPoints);
    for(int i = 0 ; i < DRAWAREA_LEN ; i++)
    {
        wavePointsLoc[i] = ((DRAWAREA_OFFSET_Y + DRAWAREA_WID) - mouseLoc[i]);
    }

//    if(samplingPoints == DRAWAREA_LEN)
//    {
//        for(int i = 0 ; i < DRAWAREA_LEN ; i++)
//        {
//            datatoWrite[i] = (int)((wavePointsLoc[i] / (double)DRAWAREA_WID)
//                    *(2 << (waveResolution-1)));
//        }
//    }
//    else if(samplingPoints != DRAWAREA_LEN)
//    {
        double samplingStep = ((double)DRAWAREA_LEN / (double)samplingPoints);
        int LocA,LocB;
        datatoWrite.reserve(samplingPoints);
        datatoGenerate.reserve(samplingPoints);
        waveDisplayLoc.reserve(samplingPoints);
        for(double i = 0 ; i < (samplingPoints) ; i++)
        {

            if(((samplingStep * i)-(int)(samplingStep * i)) != 0)
            {
                LocA = (int)(samplingStep * i);
                LocB = LocA + 1;
                datatoGenerate[i] = (double)(((wavePointsLoc[LocB] - wavePointsLoc[LocA]) / (LocB - LocA))   //Density
                        * ((samplingStep * i)-(int)(samplingStep * i))                              //increment
                        + wavePointsLoc[LocA]);                                                     //offset
            }
            else
            {
                datatoGenerate[i]  = (double)wavePointsLoc[(int)(samplingStep * i)];
            }
            datatoWrite[i] = (int)((long double)(datatoGenerate[i] / (long double)DRAWAREA_WID)
                    * (long double)(2 << (waveResolution-1)));
//        }
        //QMessageBox::information(this,tr("WaveSave"),tr("OK!"),QMessageBox::Ok);

    }

//    int DisResolution = waveResolution;
//    if(waveResolution > 9)
//        DisResolution = 9;
    if(samplingPoints <= DRAWAREA_LEN)
    {
        for(int i = 0 ; i < samplingPoints ; i++)
        {
            waveDisplayLoc[i] = (DRAWAREA_OFFSET_Y + DRAWAREA_WID)
                    - (int)((datatoGenerate[i] / (double)DRAWAREA_WID)*(2 << (8)));
        }
    }
    else
    {
        double XStep = samplingPoints / (double)DRAWAREA_LEN;
        for(int i = 0 ; i < DRAWAREA_LEN ; i++)
        {
            waveDisplayLoc[i] = (DRAWAREA_OFFSET_Y + DRAWAREA_WID)
                    - (int)((datatoGenerate[(int)(i * XStep)] / (double)DRAWAREA_WID)*(2 << (8)));
        }
//        waveDisplayLoc[DRAWAREA_LEN] = (DRAWAREA_OFFSET_Y + DRAWAREA_WID)
//                - (int)((datatoGenerate[samplingPoints - 1] / (double)DRAWAREA_WID)*(2 << 8));
    }

    drawWave::update();
}

void drawWave::waveSave()
{
    QString writePath = ui->lineEdit_filePath->text();
    QFile waveFile(writePath);

    if (!waveFile.open(QIODevice::WriteOnly))
    {
        QMessageBox::critical(this,tr("Error"),tr("Can not Creat File!"),QMessageBox::Ok);
        return;
    }
    waveFile.write((const char *)&waveResolution,sizeof(int));      //write resolution
    waveFile.write((const char *)&waveSamplingPoints,sizeof(int));  //write sampling points
    int writeDat;
    for(int i = 0; i < samplingPoints ; i++)
    {
        writeDat = datatoWrite[i];
        //waveFile.write((const char *)&datatoWrite[i],sizeof(int));
        waveFile.write((const char *)(&writeDat),sizeof(int));
    }
    waveFile.close();

    QMessageBox::information(this,tr("WaveSave"),tr("Save Successful!"),QMessageBox::Ok);
}

void drawWave::on_pushButton_drawWave_clicked()
{
    if(drawingFlag == ON_WAVE_DRAWING)  //start generating and enable to clean
    {
        drawingFlag = ON_WAVE_GENERATE;

        ui->pushButton_drawWave->setText("Clean");
        waveGenerate();
    }
//    else if(drawingFlag == ON_WAVE_GENERATE)
//    {

//    }
    else if((drawingFlag == ON_WAVE_GENERATE)||(drawingFlag == ON_WAVE_SAVED))   //initialize and prepare for next drawing
    {
        drawingFlag = ON_WAVE_DRAWING;

        ui->pushButton_drawWave->setText("Generate");
        for(int i = 0;i < DRAWAREA_LEN ; i++)
            //mouseLoc[i] = (DRAWAREA_WID+DRAWAREA_OFFSET_Y);
            mouseLoc[i] = DRAWAREA_OFFSET_Y+DRAWAREA_WID;
        drawWave::update();
    }

}

void drawWave::on_pushButton_saveWave_clicked()
{
    /*if(drawingFlag == ON_WAVE_DRAWING)
    {
        QMessageBox::information(this,tr("Tip"),tr("Please Generate Wave First"),QMessageBox::Ok);
        return;
    }
    else
    {
        drawingFlag = ON_WAVE_SAVED;
        ui->pushButton_drawWave->setText("Clean");
        waveSave();
    }*/
    if(drawingFlag == ON_WAVE_DRAWING)
    {
        waveGenerate();
    }
    drawingFlag = ON_WAVE_SAVED;
    ui->pushButton_drawWave->setText("Clean");
    waveSave();
}

void drawWave::on_spinBox_resolution_valueChanged(int arg1)
{
    if((drawingFlag == ON_WAVE_GENERATE)||(drawingFlag == ON_WAVE_SAVED))
    {
        drawingFlag = ON_WAVE_DRAWING;
        ui->pushButton_drawWave->setText("Generate");
    }
    waveResolution = arg1;
}

void drawWave::on_spinBox_samplingPoints_valueChanged(int arg1)
{
    if((drawingFlag == ON_WAVE_GENERATE)||(drawingFlag == ON_WAVE_SAVED))
    {
        drawingFlag = ON_WAVE_DRAWING;
        ui->pushButton_drawWave->setText("Generate");
    }
    waveSamplingPoints = arg1;
//    if(arg1 > waveSamplingPoints)   //increase
//    {
//        waveSamplingPoints = (arg1-1) * 2;
//    }
//    else
//    {
//        waveSamplingPoints = (arg1+1) / 2;
//    }
    //ui->spinBox_samplingPoints->setValue(waveSamplingPoints);
}



void drawWave::on_pushButton_Browse_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this,tr("Save"),ui->lineEdit_filePath->text());
    if(!fileName.isEmpty())
        ui->lineEdit_filePath->setText(fileName);
}
